//
// Created by LiuYou on 2021/8/21.
//



#include <cstdlib>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <cerrno>
#include <sys/wait.h>


/**
 * @brief
 * 调试父进程: show follow-fork-mode
 * <P>
 * parent (注意: gdb默认是fork()调用后调试父进程的。)
 * <p>
 * set follow-fork-mode child 即可在fork()后, 让gdb调试子进程。
 * <p>
 * 设置调试模式: set detach-on-fork off (注意: 缺省是on。)
 * <p>
 * on表示调试当前进程的时候, 其它进程继续运行。
 * <p>
 * off表示调试当前进程的时候, 其它进程被gdb挂起。
 * <p>
 * @return
 */
int main(int argc, char** argv) {
    char name[] = {"liu you"};

    fflush( nullptr );
    pid_t pid = fork();
    if (pid == -1) {
        fprintf( stderr, "fork(): %s", strerror(errno));
        exit( 1 );
    } else if (pid == 0) {
//        sleep( 3 );
        printf( "[%d]: 子进程创建成功, 子进程执行。\n", getpid());
        fflush( nullptr );

        fprintf( stdout, "name = %s\n", name );
        fflush( nullptr );

        fprintf( stdout, "[%d]: 子进程继续进行。\n", getpid());
        fflush( nullptr );

        exit( 0 );
    } else {
//        sleep( 3 );
        printf( "[%d]: 父进程执行\n", getpid());
        fflush( nullptr );

        printf( "[%d]: 父进程在工作。\n", getpid());
        fflush( nullptr );
        wait( nullptr );
    }


    exit( 0 );
}

/*
 * todo 笔记: 我在 linux的 GDB中试着调试了一下, 确实这是CLion继承的GDB的问题, 是CLion没有配置继承GDB的多进程和多线程。所以
 *  才有这个问题: 退出子进程或者创建出来的线程后 CLion就终止调试了。
 *
 * todo 笔记: 在刚刚linux命令行中使用GDB调试本程序时, 注意到切换进程不能通过 inferior PID 来切换, 而是要先 info threads,
 *  然后, thread tid 才能切换进程。在gdb上调试时, 退出子进程后, gdb还是会继续调试直到完成。这也说明了这是CLion的问题。
 *  希望CLion开发团队可以解决这个问题。
 */
































/*
Breakpoint 1, main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiProcess/Main.cpp:30
30	    pid_t pid = fork();
(gdb) show follow-fork-mode
Debugger response to a program call of fork or vfork is "parent".
(gdb) show detach-on-fork
Whether gdb will detach the child of a fork is on.
(gdb) set follow-fork-mode child
(gdb) set detach-on-fork off
[Attaching after process 7713 fork to child process 7778]
[New inferior 2 (process 7778)]
Missing separate debuginfos, use: yum debuginfo-install glibc-2.28-151.el8.x86_64 libgcc-8.4.1-1.el8.x86_64 libstdc++-8.4.1-1.el8.x86_64
Reading symbols from /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01...done.
[Switching to process 7778]

Thread 2.1 "MultiProcess01" hit Breakpoint 3, main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiProcess/Main.cpp:38
warning: Source file is more recent than executable.
38	        fprintf( stdout, "name = %s\n", name );
(gdb) info inferiors
  Num  Description       Executable
  1    process 7713      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
* 2    process 7778      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01

// todo 笔记: 到这里后使用
(gdb) inferior 1
[Switching to inferior 1 [process 7713] (/home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01)]
[Switching to thread 1.1 (process 7713)]
#0  0x00007ffff71a4e3c in fork () from /lib64/libc.so.6
(gdb) info inferiors
  Num  Description       Executable
  1    process 7713      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
* 2    process 7778      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
// todo 笔记: 这个是不能切换进程的, 在CLion中。那么如何切换到父进程中呢? 点击 Frames 切换到另外一个线程(在CLion中设计成了线程。其实
// todo 笔记: 是进程。) 然后这个时候在GDB中输入
(gdb) info inferiors
  Num  Description       Executable
* 1    process 7713      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
  2    process 7778      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
// todo 笔记: 才会进入到父进程中。
// todo 笔记: 但是, 此时点击下一步后, CLion还是会在子进程中调试。我不知道如何再转回到父进程中?
// todo 笔记: 刚刚不知道怎么回事, 我就是想在GDB中输入n, 回车后CLion的调试回到了父进程中。这个时候点单步调试调试就是父进程的。WC。
// todo 笔记: 有点激动, 其它方法都不行, 这个唯一的方法。
(gdb) n
Single stepping until exit from function fork,
which has no line number information.
main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiProcess/Main.cpp:31
31	    if (pid == -1) {

Thread 1.1 "MultiProcess01" hit Breakpoint 2, main (argc=1, argv=0x7fffffffe9d8) at /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/src/MultiProcess/Main.cpp:57
57	        printf( "[%d]: 父进程执行\n", getpid());
// todo 笔记: 这个时候我想再返回子进程怎么办? 还是刚刚的办法: 先在CLion的Frames下选择子进程对应的Thread(在这个程序中是Thread-2, 其实
// todo 笔记: 是进程, 不过CLion把名字叫成了线程。), 然后在GDB中输入 n(注意这里不能在CLion的图形化那里点击单步(这样的话CLion还是调试的之前调试的进程),
// todo 笔记: 而必须要在GDB中输入n, CLion才能切换了进程进行调试。)
(gdb) info inferiors
  Num  Description       Executable
* 1    process 7713      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
  2    process 7778      /home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
(gdb) n
54	        exit( 0 );
// todo 笔记: 这里是调试到了子进程的最后一句。


// todo 笔记: 总结, 在CLion中调试多进程就要将CLion的图形化的下一步调试等CLion的各种调试工具与 GDB命令行结合起来才行！！！！
// todo 笔记: 不过现在还有一个不懂的问题就是, 当子进程和父进程都运行到了最后一步, 如: 本程序子进程到 exit( 0 ); 后, 子进程如何返回到
// todo 笔记: 父进程中呢? 我试过了, 在子进程中执行下一步后, CLion的下一步 和 GDB的n 都不会返回到父进程中。
// todo 笔记: GDB给的反馈是
(gdb) n
[Inferior 2 (process 9175) exited normally]
// todo 笔记: 然后子进程正常退出后, 父进程直接退出了
/home/liuyou/CLionProjects/MultiProcessAndMultiThreadDebug/cmake-build-debug/src/MultiProcess/MultiProcess01
[9175]: 子进程创建成功, 子进程执行。
name = liu you
[9175]: 子进程继续进行。
[9107]: 父进程执行

Process finished with exit code 1
// todo 笔记: 并没有将父进程的
printf( "[%d]: 父进程在工作。\n", getpid());
// todo 笔记: 代码中的内容执行出来。
// todo 笔记: CLion的反馈也是一样的。

// todo 笔记: 目前没有找到一个方法可以解决这个问题。:(

// 此外，如果想让父子进程都同时运行，可以使用“set schedule-multiple on”（默认schedule-multiple是off）命令。
// 注意: 这个命令我试过了, 不要使用。使用上面总结的办法就可以进行多进程的调试。

// todo 笔记: 最后总结: 可以在CLion中进行过多进程的调试, 但是有一个问题是子进程退出后, 父进程也会直接错误退出。这个问题当前解决不了。
*/